﻿using NewLife;
using NewLife.Serialization;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace EOH.IoTCard.UPIoT
{
    public class UPIoTRequest<TResponse> : IRequest<TResponse>
    {
        string? _ApiKey;
        public virtual string? ApiKey { get => _ApiKey; set { _ApiKey = value; _PrefixUlr = $"/api/v2/{value}"; } }
        string? _PrefixUlr;
        public virtual string? PrefixUlr => _PrefixUlr;
        public virtual string? Url { get; }
        public virtual HttpMethod Method => HttpMethod.Post;
        public TResponse? ConvertResponse(string content) { if (string.IsNullOrWhiteSpace(content)) { return default; } return content.ToJsonEntity<TResponse>(); }
    }
    public class UPIoTRequest<TModel, TResponse> : UPIoTRequest<TResponse> , IRequest<TModel,TResponse>
    {
        public TModel? Model { get; set; }
    }
    public class UPIoTResponse{
        /// <summary>状态码 200成功</summary>
        public int code { get; set; }
        /// <summary>信息</summary>
        public string? msg { get; set; }
        /// <summary>是否成功</summary>
        public bool IsSuccess => code == 200;
    }
    public class UPIoTResponse<TResponse> : UPIoTResponse
    {
        public TResponse data { get; set; }
    }
    /// <inheritdoc/>
    public class UPIoTService : IService
    {
        #region 属性
        readonly IHttpClientFactory? _HttpClientFactory;
        readonly UPIoTOptions? _UPIotOptions;
        static string _HttpClientFactoryName = typeof(UPIoTService).FullName;
        #endregion

        #region 构造函数
        /// <summary>构造函数</summary>
        /// <param name="HttpClientFactory"></param>
        /// <param name="options"></param>
        public UPIoTService(IHttpClientFactory? HttpClientFactory, UPIoTOptions? options)
        {
            _HttpClientFactory = HttpClientFactory;
            _UPIotOptions = options;
        }
        #endregion
        /// <inheritdoc/>
        public Task<TResponse> Execute<TResponse>(IRequest<TResponse> request) => Send(request);
        /// <inheritdoc/>
        public Task<TResponse> Execute<TModel, TResponse>(IRequest<TModel, TResponse> request) => Send(request, request.Model);

        async Task<TResponse> Send<TResponse>(IRequest<TResponse> request, object model = null)
        {
            try
            {
                if (_UPIotOptions is null || string.IsNullOrWhiteSpace(_UPIotOptions.ApiKey) || string.IsNullOrWhiteSpace(_UPIotOptions.ApiSecret)) { throw new Exception($"{nameof(UPIoTOptions)} 配置参数有误"); }
                if (request is not UPIoTRequest<TResponse> upiotrequest) { throw new Exception($"{nameof(request)} 非UPIoT接口参数实体"); }
                upiotrequest.ApiKey = _UPIotOptions.ApiKey;
                using var client = _HttpClientFactory?.CreateClient(_HttpClientFactoryName);
                var url = BuildSignaUrl(upiotrequest, model);
                if (client is null || string.IsNullOrWhiteSpace(url)) { throw new Exception("CreateClient or url is null"); }
                using var upiotRequest = new HttpRequestMessage(upiotrequest.Method, url);
                if (HttpMethod.Post == request.Method) {
                    var content = model?.ToJson();
                    upiotRequest.Content = new StringContent(content, Encoding.UTF8, "application/json");
                }
                using var response = await client.SendAsync(upiotRequest);
                response.EnsureSuccessStatusCode();
                var res = await response.Content.ReadAsStringAsync();
                var data = request.ConvertResponse(res);
                return data;
            }
            catch (Exception) { throw; }
        }

        string BuildSignaUrl<TResponse>(UPIoTRequest<TResponse> request, object model)
        {
            //注意：这里url拼接，带参数拼接符号 /?
            if (HttpMethod.Get == request.Method)
            {
                var dic = model?.ToDictionary();
                var param = dic?.Select(o => $"{o.Key}={o.Value}").ToList() ?? new List<string>();
                var sign = $"{string.Join(string.Empty, param)}{_UPIotOptions.ApiSecret}".MD5().ToLower();
                param.Add($"_sign={sign}");
                return $"{request.PrefixUlr}{request.Url}/?{string.Join("&", param)}";
            }
            else if (HttpMethod.Post == request.Method)
            {
                var sign = $"{model?.ToJson()}{_UPIotOptions.ApiSecret}".MD5().ToLower() ;
                return $"{request.PrefixUlr}{request.Url}/?_sign={sign}";
            }
            return string.Empty;
        }
    }
}
